package resml

import (
	"io"
	"os"
	"path/filepath"
	"strings"
)

// 创建并文件：自动创建所在目录。如果 append 为 true，则以 append 模式打开；否则清空原数据后打开。
func FileCreate(path string, append bool) (*os.File, error) {
	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
		return nil, err
	}
	if append {
		return os.OpenFile(path, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	}
	return os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
}

// 判断目录是否为空
func DirIsEmpty(path string) bool {
	empty, _, _ := DirIsEmptyExists(path)
	return empty
}

// 判断目录是否为空，是否存在
func DirIsEmptyExists(path string) (empty, exists, dir bool) {
	fd, err := os.Open(path)
	if err != nil { // 不存在就是空
		empty = os.IsNotExist(err)
		exists = !empty
		return
	}
	defer fd.Close()
	if stat, err := fd.Stat(); err != nil || !stat.IsDir() {
		return false, true, stat.IsDir() // 出错或不是目录，则不能判断为空
	}
	_, err = fd.Readdirnames(1)
	return err == io.EOF, true, true
}

// 获取绝对路径，如果已经是绝对路径则返回已清理干净的路径
func PathAbsolute(path string) (string, error) {
	if filepath.IsAbs(path) {
		return filepath.Clean(path), nil
	}
	return filepath.Abs(path)
}

// 删除文件或目录，如果父目录为空，则一并删除，直到 root 为止。root 目录本身不会删除。
func FileRemove(path, root string) (err error) {
	if root, err = PathAbsolute(root); err != nil {
		return
	}
	if path, err = PathAbsolute(path); err != nil {
		return
	}
	if !strings.HasPrefix(path, root+string(os.PathSeparator)) {
		return nil // 不在 root 目录下，返回
	}
	empty, exists, isdir := DirIsEmptyExists(path)
	if !exists { // 不存在，删除父目录
		return FileRemove(filepath.Dir(path), root)
	} else if isdir && !empty {
		return nil // 目录，且不为空，返回
	}
	if err = os.Remove(path); err != nil { // 目录当前文件/目录
		return
	}
	return FileRemove(filepath.Dir(path), root) // 删除父目录
}

// 文件重命名，自动创建目标文件所在的目录；如果 oldroot 不为空，则删除 oldroot 下的 oldpath 的空的父目录。
func FileRename(oldpath, newpath, oldroot string) error {
	if stat, err := os.Stat(newpath); err == nil {
		if !stat.IsDir() {
			return os.ErrExist
		}
	} else {
		if err := os.MkdirAll(filepath.Dir(newpath), 0755); err != nil { // 创建目标目录
			return err
		}
	}
	if err := os.Rename(oldpath, newpath); err != nil { // 重命名
		return err
	}
	if oldroot != "" { // 删除旧目录
		return FileRemove(filepath.Dir(oldpath), oldroot)
	}
	return nil
}
